package com.example.demo.common.component;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.demo.project.dao.QQUserDao;
import com.example.demo.project.entity.QQNews;
import com.example.demo.project.entity.QQUser;
import com.example.demo.project.entity.User;
import com.example.demo.project.entity.qqto.OneNews;
import com.example.demo.project.entity.qqto.OneUser;
import com.example.demo.project.service.UserService;
import com.mongodb.client.result.UpdateResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author websocket服务
 */
@ServerEndpoint(value = "/imserver/{username}")
@Component
public class WebSocketServer {

    public static UserService userService;
    public static MongoTemplate mongoTemplate;
    public static QQUserDao qqUserDao;

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 记录当前在线连接数
     */
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        sessionMap.put(username, session);
        log.info("有新用户加入，username={}, 当前在线人数为：{}", username, sessionMap.size());
        type0(session,username);
        type1();
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("username") String username) {
        sessionMap.remove(username);
        log.info("有一连接关闭，移除username={}的用户session, 当前在线人数为：{}", username, sessionMap.size());
        type2(username);
        type1();
    }

    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("username") String username) {
        log.info("服务端收到用户username={}的消息:{}", username, message);
        JSONObject obj = JSONUtil.parseObj(message);
        //私聊
        if(obj.getStr("type").equals("0")){
            type3(obj,username);
        }
        //        群聊
        else if(obj.getStr("type").equals("1")){
            type4(obj);
        }
        //同意好友
        else if(obj.getStr("type").equals("2")){
            String username1=obj.getStr("username");
            qqUserDao.applyFriend(username,username1,false);
            String uuid = IdUtil.fastSimpleUUID();
            //新增自己
            QQUser qqUser= qqUserDao.findOneQQUser(username);
            OneUser oneUser = new OneUser();
            oneUser.setUsername(username1);
            oneUser.setNewsId(uuid);
            qqUser.getUserList().add(oneUser);
            Query query = new Query(Criteria.where("username").is(username));
            Update update= new Update().set("userList", qqUser.getUserList());
            UpdateResult result =mongoTemplate.updateFirst(query,update, QQUser.class);
            //新增对方
            QQUser qqUser1= qqUserDao.findOneQQUser(username1);
            OneUser oneUser1 = new OneUser();
            oneUser1.setUsername(username);
            oneUser1.setNewsId(uuid);
            qqUser1.getUserList().add(oneUser1);
            Query query1 = new Query(Criteria.where("username").is(username1));
            Update update1= new Update().set("userList", qqUser1.getUserList());
            UpdateResult result1 =mongoTemplate.updateFirst(query1,update1, QQUser.class);
            //新增消息库
            QQNews qqNews = new QQNews();
            List<OneNews> oneNewsList = new LinkedList();
            OneNews oneNews = new OneNews(username1,"你好");
            oneNewsList.add(oneNews);
            qqNews.setNewsId(uuid);
            qqNews.setNews(oneNewsList);
            mongoTemplate.insert(qqNews);
            //添加完后再初始化
            Session toSession = sessionMap.get(username1);
            type0(session,username);
            type0(toSession,username1);
            type1();
        }
//        拒绝好友
        else if(obj.getStr("type").equals("3")){
            String username1=obj.getStr("username");
            qqUserDao.applyFriend(username,username1,false);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 服务端发送消息给客户端
     */
    private void sendMessage(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     * 服务端发送消息给所有客户端
     */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
    //每次登入发送自己的好友列表
    public void type0(Session session,String username){
        QQUser qqUserOne = qqUserDao.findOneQQUser(username);
        List<OneUser> userList = qqUserOne.getUserList();
        JSONObject result = new JSONObject();
        JSONArray array1 = new JSONArray();
        for(int i=0;i<userList.size();i++){
            QQNews qqNews = qqUserDao.findOneQQNews(userList.get(i).getNewsId());
            User user = userService.getUser(userList.get(i).getUsername());
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("username",user.getUsername());
            jsonObject.set("name",user.getName());
            jsonObject.set("img",user.getImg());
            jsonObject.set("message",qqNews.getNews().get(qqNews.getNews().size()-1).getMessage());
            jsonObject.set("newsId",userList.get(i).getNewsId());
            array1.add(jsonObject);
        }
        result.set("type","0");
        result.set("users", array1);
        sendMessage(JSONUtil.toJsonStr(result),session);
    }
    public void type1(){
        //每次登入发送所有在线用户
        JSONObject lineUsers  = new JSONObject();
        JSONArray array = new JSONArray();
        for (Object key : sessionMap.keySet()) {
            array.add(key);
        }
        lineUsers.set("type","1");
        lineUsers.set("lineUsers", array);
        sendAllMessage(JSONUtil.toJsonStr(lineUsers));
    }
    public void type2(String username){
        //每次有人下线时发送下线用户
        JSONObject offLineUsers  = new JSONObject();
        offLineUsers.set("offLineUsers", username);
        offLineUsers.set("type","2");
        sendAllMessage(JSONUtil.toJsonStr(offLineUsers));
    }
    public void type3(JSONObject obj,String username){
        //私聊发送消息
        String newsId = obj.getStr("newsId");
        String toUsername = obj.getStr("to"); // to表示发送给哪个用户，比如 admin
        String text = obj.getStr("text"); // 发送的消息文本  hello
        qqUserDao.newsInsert(username,newsId,text);
        Session toSession = sessionMap.get(toUsername); // 根据 to用户名来获取 session，再通过session发送消息文本
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("from", username);
        jsonObject.set("text",text);
        jsonObject.set("type","3");
        this.sendMessage(jsonObject.toString(), toSession);
        log.info("发送给用户username={}，消息：{}", toUsername, jsonObject.toString());
    }
    public void type4(JSONObject obj){
        //群聊发送消息
        String name = obj.getStr("name"); // to表示发送给哪个用户，比如 admin
        String img = obj.getStr("img"); // to表示发送给哪个用户，比如 admin
        String text = obj.getStr("text"); // 发送的消息文本  hello
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("name", name);
        jsonObject.set("text",text);
        jsonObject.set("img",img);
        jsonObject.set("num",sessionMap.size());
        jsonObject.set("type","4");
        this.sendAllMessage(jsonObject.toString());
    }
}
